package org.layuiframework.stereotype.security;

import org.layuiframework.stereotype.security.bean.AbstractUser;
import org.layuiframework.stereotype.security.impl.AbstractUserGetter;
import org.layuiframework.stereotype.security.impl.LoginAttemptService;
import org.layuiframework.stereotype.util.RSAUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * 自定义用户身份认证
 */
@Component
public class UserAuthenticationProvider implements AuthenticationProvider {

    @Resource
    RSAUtils utils;

    @Resource
    LoginAttemptService attempt;

    @Lazy
    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    AbstractUserGetter abstractUserGetter;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getName();
        if (attempt.isBlocked(username)) throw new LockedException("账号被锁定，请30分钟后再试");
        String presentedPassword = (String) authentication.getCredentials();
        if (presentedPassword == null) throw new BadCredentialsException("登录名或密码错误");
        else try {
            presentedPassword = utils.decrypt(presentedPassword);
        } catch (Exception e) {
            throw new BadCredentialsException("登录名或密码错误");
        }
        // 根据用户名获取用户信息
        AbstractUser user = abstractUserGetter.getUser(username);
        if (user == null) throw new BadCredentialsException("用户名不存在");
        else {
            // 自定义的加密规则，用户名、输的密码和数据库保存的盐值进行加密
            if (authentication.getCredentials() == null || !passwordEncoder.matches(presentedPassword, user.getSecurityPassword()))
                throw new BadCredentialsException("登录名或密码错误");
            else {
                List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
                user.getSecurityRole().stream().forEach(roleId -> grantedAuthorities.add(new SimpleGrantedAuthority(roleId)));
                UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(user, authentication.getCredentials(), grantedAuthorities);
                result.setDetails(authentication.getDetails());
                return result;
            }
        }
    }

    @Override
    public boolean supports(Class<?> authentication) {
        // TODO Auto-generated method stub
        return true;
    }

}
